<?php

namespace Caifenglei\AuthRbac\Http\Controllers;

use Caifenglei\AuthRbac\Http\Actions\UserAction;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Tymon\JWTAuth\JWTGuard;

class AuthController extends Controller
{
    public function login(Request $request)
    {
        $request->validate([
            'username' => 'required|string|max:100',
            'password' => 'required|string',
        ]);

        $credentials = [
            'username' => $request->username,
            'password' => $request->password,
        ];
        $token = $this->getAuthGuard()->attempt($credentials);
        if (!$token) {
            return $this->fail('登录失败，用户名或密码错误');
        }

        $payload = $this->getAuthGuard()->payload();
        $user = $this->getAuthGuard()->user();
        $response_data = [
            "access_token" => $token,
            "token_type" => "bearer",
            "expires_in" => $payload->get('exp'),
            "user" => $user->toArray()
        ];
        return $this->success('登录成功', $response_data);
    }

    public function register(Request $request){
        $request->validate([
            'email' => 'required|string|email|max:255|unique:users,username',
            'password' => 'required|string|min:6',
        ]);

        $user = UserAction::getUserClass()::create([
            'username' => $request->email,
            'password' => Hash::make($request->password),
            'last_ip' => $request->getClientIp(),
            'last_time' => now()
        ]);

        $token = $this->getAuthGuard()->login($user);
        $payload = $this->getAuthGuard()->payload();
        return $this->success('注册成功', [
            'user' => $user,
            "access_token" => $token,
            "token_type" => "bearer",
            "expires_in" => $payload->get('exp'),
        ]);
    }

    protected function getAuthGuard() : JWTGuard 
    {
        return Auth::guard('api');
    }

    /**
     * 跳转到统一登录获取code授权码
     * @param Request $request
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Foundation\Application|\Illuminate\Http\RedirectResponse|\Illuminate\Routing\Redirector
     */
    public function redirect_to_sso(Request $request) {
        $request->session()->put('state', $state = Str::random(40));

        $query = http_build_query([
            'client_id' => config('auth-rbac.sso.client_id'),
            'redirect_uri' => $this->getRedirectUrl($request),
            'response_type' => 'code',
            // 'scope' => '',
            // 'state' => $state,
            // 'prompt' => '', // "none", "consent", or "login"
        ]);

        return redirect(config('auth-rbac.sso.authorize_url').'?'.$query);
    }

    /**
     * oAuth认证的重定向回调
     * @param Request $request
     * @return array|\Illuminate\Http\JsonResponse|mixed
     */
    public function callback(Request $request) {
        $code = $request->input('code', '');

        if (empty($code)) {
            return $this->fail('获取code失败');
        } else {
            $post_data = [
                'grant_type' => 'authorization_code',
                'client_id' => config('auth-rbac.sso.client_id'),
                'client_secret' => config('auth-rbac.sso.client_secret'),
                'redirect_uri' => $this->getRedirectUrl($request),
                'code' => $code,
            ];
            $response = Http::asForm()->post(config('auth-rbac.sso.token_url'), $post_data);

            if($response->failed()){
                Log::error('sso response data...', $response->json());
                return $this->fail('获取token失败');
            }else{
                $auth_info = $response->json();
                $sso_version = config('auth-rbac.sso.profile_version');
                if($sso_version == 'self'){
                    //自有统一登录
                    $profile_response = Http::withToken($auth_info['access_token'])
                        ->get(config('auth-rbac.sso.server_host').'/api/v1/user/profile');
                    if($profile_response->failed()){
                        return $this->fail('获取用户信息失败');
                    }else{
                        $profile = $profile_response->json();
                        $user_info = $profile['data'];
                        $login_info = UserAction::ssoUserLogin($user_info);
                        return $this->success('统一认证登录成功', $login_info);
                    }
                }else if($sso_version == 'c30'){
                    //沐坤平台
                    $login_info = UserAction::c30SsoUserLogin($auth_info);
                    return $this->success('统一认证登录成功', $login_info);
                }
            }
        }
    }

    /**
     * 统一认证退出登录
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function logout(Request $request) {
        $is_mobile = $request->has('mobile');
        $config_key = $is_mobile ? 'auth-rbac.sso.mobile_logout_url' : 'auth-rbac.sso.logout_url';

        return redirect(config($config_key));
    }

    /**
     * 获取登录用户信息
     */
    public function user(Request $request) {
        $user = $this->getAuthGuard()->user();
        return $this->success('获取用户信息成功', ["user" => $user->toArray()]);
    }

    /**
     * 为支持开发和测试多环境的前端重定向
     * @param Request $request
     * @return mixed|string
     */
    private function getRedirectUrl(Request $request) {
        $referer_url = $request->header('referer');
        $is_mobile = $request->has('mobile');
        $config_key = $is_mobile ? 'auth-rbac.sso.mobile_redirect_uri' : 'auth-rbac.sso.redirect_uri';
        if($referer_url) {
            $referer_parsed = parse_url($referer_url);
            $port = Arr::get($referer_parsed, 'port');
            $redirect_domain = $referer_parsed['scheme'].'://'.$referer_parsed['host'].($port ? ':'.$port : '');
            $redirect_uri = $redirect_domain.parse_url(config($config_key))['path'];
        }else{
            $redirect_uri = config($config_key);
        }

        return $redirect_uri;
    }
}
